//* --------------------------------------------
//* Utilities ----------------------------------
//* --------------------------------------------
//* --------------------------------------------

void computeBestLabelPosition(int layerID){
  
  if ( layerID != 2) return;
  
  float slope_deg_u_prev = 0;
  float slope_deg_l_prev = 0;
  float min_offset = mainPlotX2 - mainPlotX1;
  ArrayList<Float> x_ch = new ArrayList<Float>();
  ArrayList<Integer> pos_ch = new ArrayList<Integer>();
  ArrayList<Float> y_ch = new ArrayList<Float>();
  ArrayList<Float> offset_ch = new ArrayList<Float>();
  
   //calculate range first
    int low = (int)map(ltimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData);
    int upper = (int)map(rtimeSliderPos, timeScrollBarX1, timeScrollBarX2, 0, controller.numData); 
  
    Label label = new Label();
    Label prevLabel = new Label();
    
    for(int pos = low + 1; pos < upper - 1; pos++){
      float value_u =  controller.getUpperData(layerID, pos);
      float value_l =  controller.getLowerData(layerID, pos);
      
      float x = map(pos, low, upper - 1, mainPlotX1, mainPlotX2);
      float y_u = map(value_u, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);
      float y_l = map(value_l, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);
      
      float value_u_prev =  controller.getUpperData(layerID, pos - 1);
      float value_l_prev =  controller.getLowerData(layerID, pos - 1);
      float y_u_prev = map(value_u_prev, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);
      float y_l_prev = map(value_l_prev, dataMin, dataMax, mainPlotY2 - 20, mainPlotY1 + 20);
      
      
      float x_prev = map(pos-1, low, upper - 1, mainPlotX1, mainPlotX2);
      float offset = abs(y_u - y_l);
      float slope_rad_u = atan( (y_u - y_u_prev) / abs(x - x_prev));
      float slope_deg_u = (float)Math.toDegrees(slope_rad_u);
      
      //println(slope_deg_u + "==" + slope_deg_u_prev );
      
      if ( slope_deg_u_prev == 0 ) {
        if( slope_deg_u > 15 ) {
          x_ch.add(x);
          pos_ch.add(pos);
          y_ch.add(y_u);
          offset_ch.add(offset);
          
        }
      }else {
        if( abs(slope_deg_u - slope_deg_u_prev)  > 15 ) {
          //println(slope_deg_u  + "    " + slope_deg_u_prev + "       " + (abs (slope_deg_u - slope_deg_u_prev) / (slope_deg_u_prev > slope_deg_u ? slope_deg_u_prev : slope_deg_u) ) * 100);
          if (slope_deg_u >= 0){
              x_ch.add(x);
              pos_ch.add(pos);
              y_ch.add(y_u);
              offset_ch.add(offset);
          }else{
              x_ch.add(x_prev);
              pos_ch.add(pos - 1);
              y_ch.add(y_u_prev);
              offset_ch.add(abs(y_u_prev - y_l_prev));
          }
          
          
        }
        
      }
      
      slope_deg_u_prev = slope_deg_u;
      
      float slope_rad_l = atan( (y_l - y_l_prev) / abs(x - x_prev));
      float slope_deg_l = (float)Math.toDegrees(slope_rad_l);
      
      if ( slope_deg_l_prev == 0 ) {
        if( slope_deg_l > 15) {
          x_ch.add(x);
          pos_ch.add(pos);
          y_ch.add(y_l);
          offset_ch.add(offset);
        }
      }else {
        if( abs(slope_deg_l - slope_deg_l_prev) > 15 ) {
          if (slope_deg_l < 0){
              x_ch.add(x);
              pos_ch.add(pos);
              y_ch.add(y_l);
              offset_ch.add(offset);
          }else{
              x_ch.add(x_prev);
              pos_ch.add(pos - 1);
              y_ch.add(y_l_prev);
              offset_ch.add(abs(y_u_prev - y_l_prev));
          }
          
          

        }
        
      }
      
      slope_deg_l_prev = slope_deg_l;

      if ( offset < min_offset && offset > 30 ) min_offset = offset;
      
    }
  
  
  strokeWeight(10);
  stroke(0xFFFFFFFF);
  //println(x_ch.size());
  for(int i = 0; i < x_ch.size() - 1; i++){
    //point(x_ch.get(i), y_ch.get(i));

    if( offset_ch.get(i) < 30 && offset_ch.get(i + 1) < 30) {
      x_ch.remove(i);
      offset_ch.remove(i);
      y_ch.remove(i);
      pos_ch.remove(i);
      i = i -1;
    }  
  }
  
  fill(0xFFFFFFFF);
  for(int i = 0; i < x_ch.size() - 1; i++){
    point(x_ch.get(i), y_ch.get(i));
    text(offset_ch.get(i), x_ch.get(i) + 15, y_ch.get(i) - 5);
  }
  
  println(min_offset);
}


void computeDataMinMax(){
 dataMin = dataMax * 2;
   dataMax = -dataMax * 2;
  
   for(int pos = 0; pos < numDivisions; pos++){
      for (int layerID = controller.numLayers - 1; layerID >= 0; layerID--) {
        float g0 = controller.getg0(pos);
        
        if(dataMin > g0 + controller.getLowerOffset(layerID, pos)) dataMin = g0 + controller.getLowerOffset(layerID, pos);
        if(dataMax < g0 + controller.getUpperOffset(layerID, pos)) dataMax = g0 + controller.getUpperOffset(layerID, pos);
        
      }  
   } 
  
}

float computeTrendDataMax(){
   
   float dm = 0;
  
   for(int pos = 0; pos < numDivisions; pos++){
      for (int layerID = controller.numLayers - 1; layerID >= 0; layerID--) {

        if(dm < controller.getRealData(layerID, pos)) dm = controller.getRealData(layerID, pos);
        
      }  
   } 
   
   return dm;
  
}
  
//from wiki
void HCLtoRGB(float H, float C, float L, float[]RGB){
  H = map(H, 0, 1, 0, 360);
  
  float H_prime = H / 60;
  float X = C * ( 1 - abs(H_prime % 2 - 1))  ;
  float []rgb;
  if( 0 <= H_prime && H_prime < 1) rgb = new float[]{C, X, 0};
  else if( 1 <= H_prime && H_prime < 2) rgb = new float[]{X, C, 0};
  else if( 2 <= H_prime && H_prime < 3) rgb = new float[]{0, C, X};
  else if( 3 <= H_prime && H_prime < 4) rgb = new float[]{0, X, C};
  else if( 4 <= H_prime && H_prime < 5) rgb = new float[]{X, 0, C};
  else if( 5 <= H_prime && H_prime <= 6) rgb = new float[]{C, 0, X};
  
  else {
    rgb = new float[]{0, 0, 0};
  }
  
  float m = L - (float)( 0.3 * rgb[0] + 0.59 * rgb[1] + 0.11 * rgb[2]);
  
  float r;
  float g;
  float b;
  
  r = (rgb[0] + m);
  g = (rgb[1] + m);
  b = (rgb[2] + m);
  
  RGB[0] = (int)map(r, 0, 1, 0, 255);
  RGB[1] = (int)map(g, 0, 1, 0, 255);
  RGB[2] = (int)map(b, 0, 1, 0, 255);
}
  
  
  
float getHue(float layerID, boolean trend){
  int i = (int)map(layerID, 0, ceil(controller.numLayers/ 2), lhueSliderPos, rhueSliderPos);
  if(trend) i = (int)map(layerID, 0, controller.numLayers, lhueSliderPos, rhueSliderPos);
  if(isHueFlip == 1 || isHueFlip == 3)  i = rhueSliderPos - (i - lhueSliderPos);
  return map(i, hueScrollBarX1, hueScrollBarX2, 0, 1);
}

float getHueMaxOffset(float layerID, boolean trend){
  int i = (int)map(layerID, 0, controller.numLayers, lhueSliderPos, rhueSliderPos);
  if(trend) i = (int)map(layerID, 0, controller.numLayers, lhueSliderPos, rhueSliderPos);
  if(isHueFlip == 1 || isHueFlip == 3)  i = rhueSliderPos - (i - lhueSliderPos);
  return map(i, hueScrollBarX1, hueScrollBarX2, 0, 1);
}

float getLuma(float layerID, boolean trend){
  int i = (int)map(layerID, 0, ceil(controller.numLayers/ 2), llumaSliderPos, rlumaSliderPos);
  if(trend) i = (int)map(layerID, 0, controller.numLayers, llumaSliderPos, rlumaSliderPos);
  if(isLumaFlip == 1 || isLumaFlip == 3)  i = rlumaSliderPos - (i - llumaSliderPos);
  return map(i, lumaScrollBarX1, lumaScrollBarX2, 0, 1);
}

float getChroma(float layerID, boolean trend){
  int i = (int)map(layerID, 0, ceil(controller.numLayers/ 2), lchromaSliderPos, rchromaSliderPos);
  if(trend) i = (int)map(layerID, 0, controller.numLayers, lchromaSliderPos, rchromaSliderPos);
  if(isChromaFlip == 1 || isChromaFlip == 3)  i = rchromaSliderPos - (i - lchromaSliderPos);
  return map(i, chromaScrollBarX1, chromaScrollBarX2, 0, 1);
}

void colorLayersT(){
   
  println("IN COLOR LAYERS");
  
  if(controller.numLayers == 1){
    float hue = map(rhueSliderPos, hueScrollBarX1, hueScrollBarX2, 0, 1);
    float luma = map(rlumaSliderPos, lumaScrollBarX1, lumaScrollBarX2, 0, 1);
    float chroma = map(rchromaSliderPos, chromaScrollBarX1, chromaScrollBarX2, 0, 1);
    
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);
    controller.setColor(0, color(rgb[0], rgb[1], rgb[2], 255));
    
    color c = controller.getRealColor(0);
    //println(0 + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
    return;
    
  }
  
  boolean h_t = false;
  boolean c_t = false;
  boolean l_t = false;
  
  
  if(isHueFlip >= 2 || isChromaFlip >= 2 || isLumaFlip >= 2) {
    colorTrendLines();
    return;
  }
  
  for(int layerID =0; layerID < controller.numLayers/2; layerID++){
    float hue = getHue(layerID, h_t);
    float luma = getLuma(layerID, l_t);
    float chroma = getChroma(layerID, c_t);
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);
    controller.setColor(layerID, color(rgb[0], rgb[1], rgb[2], 255));
    //color c = controller.getRealColor(layerID);
    //println(layerID + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
  }
 
 for(int layerID = ceil(controller.numLayers/2); layerID >= 0 ; layerID--){
    float hue = getHue(layerID, h_t);
    float luma = getLuma(layerID, l_t);
    float chroma = getChroma(layerID, c_t);
    float []rgb = new float[3];

    HCLtoRGB(hue, chroma, luma, rgb);
    if( (controller.numLayers - layerID - 1) >= controller.numLayers) continue;
    controller.setColor(controller.numLayers - layerID - 1, color(rgb[0], rgb[1], rgb[2], 255 ));
    //color c = controller.getRealColor(layerID);
    //println(layerID + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
  } 
  //println("=========~~~~~~~~~~~~===========");
  
//  println("maxoffsetLayer: " + maxOffsetLayer);
//  
//  if(rhueSliderPos >= hueScrollBarX2 + 5 /*&& lhueSliderPos == hueSliderPosX1 */) return;
//  
//  println("maxoffsetLayer: " + maxOffsetLayer);
//    int layerID = maxOffsetLayer;
//    float hue = getHueMaxOffset(0, h_t);
//    float luma = getLuma(layerID, l_t);
//    float chroma = getChroma(layerID, c_t);
//    float []rgb = new float[3];
//
//    HCLtoRGB(hue, chroma, luma, rgb);
//    if( (controller.numLayers - layerID - 1) >= controller.numLayers) return;
//    controller.setColor(layerID, color(rgb[0], rgb[1], rgb[2], 255 ));
//    //color c = controller.getRealColor(layerID);
  
}



void colorLayers(){
   
  println("IN COLOR LAYERS");
  
  if(selectedColoring == 1) {
    colorLayersT();
    return;
  }
  
  if(controller.numLayers == 1){
    float hue = map(rhueSliderPos, hueScrollBarX1, hueScrollBarX2, 0, 1);
    float luma = map(rlumaSliderPos, lumaScrollBarX1, lumaScrollBarX2, 0, 1);
    float chroma = map(rchromaSliderPos, chromaScrollBarX1, chromaScrollBarX2, 0, 1);
    
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);
    controller.setColor(0, color(rgb[0], rgb[1], rgb[2], 255));
    
    color c = controller.getRealColor(0);
    //println(0 + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
    return;
    
  }
  
  boolean h_t = true;
  boolean c_t = true;
  boolean l_t = true;
  
  
//  if(isHueFlip >= 2 || isChromaFlip >= 2 || isLumaFlip >= 2) {
//    colorTrendLines();
//    return;
//  }
  
  float n = 0;
  int p = 0;
  boolean first = true;
  for(int lID = 0; lID < controllerOld.numLayers; lID++){
    if(controller.matchLayerID(lID) == -1) continue;
    
    int layerID = controller.matchLayerID(lID);
    
    //if(lerID == controloat hue = getHue(n, h_t);
    float hue = getHue(n, h_t);
    float luma = getLuma(n, l_t);
    float chroma = getChroma(n, c_t);
    float []rgb = new float[3];
   
    if(p <= controller.numLayers * 0.6 ) n += 0.5;
    else  if(p > controller.numLayers * 0.6 && p != controller.numLayers - 2)  { if( first) {n = p; first = false;} else n += 0.7 ;}
    else if(p == controller.numLayers - 2) {println("here"); n = p + 1;}
    
    p++;
    
    HCLtoRGB(hue, chroma, luma, rgb);
    controller.setColor(layerID, color(rgb[0], rgb[1], rgb[2], 255));
    //color c = controller.getRealColor(layerID);
    //println(layerID + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
  }
  
} 

void colorTrendLines(){
   
  //println("IN COLOR LAYERS");
  
  
  
  if(controller.numLayers == 1){
    float hue = map(rhueSliderPos, hueScrollBarX1, hueScrollBarX2, 0, 1);
    float luma = map(rlumaSliderPos, lumaScrollBarX1, lumaScrollBarX2, 0, 1);
    float chroma = map(rchromaSliderPos, chromaScrollBarX1, chromaScrollBarX2, 0, 1);
    
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);
    controller.setColor(0, color(rgb[0], rgb[1], rgb[2], 255));
    
    color c = controller.getRealColor(0);
    //println(0 + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
    return;
    
  }
   for(int layerID =0; layerID < controller.numLayers; layerID++){
    float hue = getHue(layerID, true);
    float luma = getLuma(layerID, true);
    float chroma = getChroma(layerID, true);
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);
    controller.setColor(layerID, color(rgb[0], rgb[1], rgb[2], 255));
    color c = controller.getRealColor(layerID);
    //println(layerID + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
  }

  //println("=========~~~~~~~~~~~~===========");
}


color getColor(int layerID){
   
  //println("IN GET COLOR:" + layerID  );
  
  if(controller.numLayers == 1){
    float hue = map(rhueSliderPos, hueScrollBarX1, hueScrollBarX2, 0, 1);
    float luma = map(rlumaSliderPos, lumaScrollBarX1, lumaScrollBarX2, 0, 1);
    float chroma = map(rchromaSliderPos, chromaScrollBarX1, chromaScrollBarX2, 0, 1);
    
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);

    return color(rgb[0], rgb[1], rgb[2], 255);
    
  }
  
   if ( layerID < controller.numLayers/2 ){
    float hue = getHue(layerID, false);
    float luma = getLuma(layerID, false);
    float chroma = getChroma(layerID, false);
    float []rgb = new float[3];
   
    HCLtoRGB(hue, chroma, luma, rgb);
    color c = color(rgb[0], rgb[1], rgb[2], 255);
    //println(layerID + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
    
    return c;
    
    
  }
 
else{
    float hue = getHue(layerID, false);
    float luma = getLuma(layerID, false);
    float chroma = getChroma(layerID, false);
    float []rgb = new float[3];

    HCLtoRGB(hue, chroma, luma, rgb);
    if( (controller.numLayers - layerID - 1) >= controller.numLayers) return color(255, 255, 255, 255 );
    color c = color(rgb[0], rgb[1], rgb[2], 255);
    //println(layerID + " : (" +  red(c) + ", " + blue(c) + ", " + green(c) + ") ");
    
    return c;
  } 

}
  
//* --------------------------------------------
//* Different g0 -------------------------------
//* --------------------------------------------
//* --------------------------------------------

float baseline(){
  return 0;
}

float themeRiver(int pos){ 
  return - 0.5 * controller.getTotalOffset(pos);
}

float wiggle(int pos){
   float g0 = 0;
   int n = 1;
   for (int layerID = controller.numLayers - 1; layerID >= 0; layerID--)
     g0 +=  (controller.numLayers - (n++)) * controller.getRealData(layerID, pos);
   
   g0 *= -1.0 / float(controller.numLayers) ;
   
   return g0;
}

float upstream(int pos){
   float g0 = 0;
   int n = 1;
   for (int layerID = controller.numLayers - 1; layerID >= 0; layerID--)
     g0 +=  (controller.numLayers - (n++)) * controller.getRealData(layerID, pos);
   
   g0 *= 1.0 / float(controller.numLayers) ;
   
   return g0;
}





//float weightedWiggle(int pos, float []center){
//   float g0 = 0;
//
//       
//   float totalOffset = controller.getTotalOffset(pos);
//   float moveUp = 0;
//   float increase = 0; 
//   float belowSize = 0;
//   center[0] = 0;
//   
//   for (int layerID = 0; layerID < controller.numLayers - 1; layerID++){
//     float offset = controller.getRealData(layerID, pos);
//     if(pos == 0){
//        increase = offset;
//        moveUp = 0.5; 
//     }else{
//        belowSize = 0.5 * offset;
//       for (int layerID2 = layerID + 1; layerID2 < controller.numLayers - 1; layerID2++)
//                belowSize += controller.getRealData(layerID2, pos);
//       increase = offset - controller.getRealData(layerID, pos - 1);
//       moveUp = (totalOffset == 0) ? 0 : (belowSize / totalOffset);
//       
//     }
//       center[0] += (moveUp - 0.5) * increase;
//     }
//     
//     
//     
//     g0 = center[0] + 0.5 * totalOffset;
//     return -g0;    
//}


float weightedWiggle(int pos){
   float g0 = 0;

       
   float totalOffset = controller.getTotalOffset(pos);
   float div = -1.f/ totalOffset;
   
   float sum = 0;
   for (int layerID = 0; layerID <= controller.numLayers - 1; layerID++){
     float offset = controller.getRealData(layerID, pos);
     
     float prev_offset = offset;
     float next_offset = offset;
     if(pos != 0) prev_offset = controller.getRealData(layerID, pos - 1);
     if(pos != controller.numData - 1) next_offset = controller.getRealData(layerID, pos + 1);
     
     float offset_der = 0.5 * 0.5  * ( next_offset - prev_offset);
     
     float o_sum = 0;
     for (int j = 1; j <= layerID - 1; j++){
       
       float j_offset = controller.getRealData(j, pos);
       
       float prev_joffset = offset;
       float next_joffset = offset;
       if(pos != 0) prev_joffset = controller.getRealData(j, pos - 1);
       if(pos != controller.numData - 1) next_joffset = controller.getRealData(j, pos + 1);
       
       o_sum +=  0.5 * ( next_joffset - prev_joffset);
        
     }
     
     sum += (offset_der + o_sum) * offset;
     
   }
   
   
   g0 = sum * div ;
   return g0;    
}


void calculateNumDivisions(){
    
    if(lock == false){
      numSamples = (int)map(numDivSliderPos, numDivScrollBarX1, numDivScrollBarX2, 1, rowCount * 0.2);
      numDivisions = rowCount / numSamples;
      
//      numDivisions = (int)map(numDivSliderPos, numDivScrollBarX1, numDivScrollBarX2, 6, rowCount);
//      numSamples = rowCount / numDivisions;
      
      lock = true;
      //onnumDivSlider = false;
      //controllerPrev = controller;
      setData(false);
      controllerPrev = controller;
      
      //sort the data
      controller.sort();
      
      addData();
      computeDataMinMax();
      colorLayers();

      lock = false;
      loop();
    }
}


void calculateNumFilters(){
    
      int diff = rnumFiltersSliderPos - lnumFiltersSliderPos;
     
      int end = (int)map(rnumFiltersSliderPos, numFiltersScrollBarX1, numFiltersScrollBarX2, 0, columnCount);
      int start = (int)map(lnumFiltersSliderPos, numFiltersScrollBarX1, numFiltersScrollBarX2, 0, columnCount);
      
      numFilterColumns = end - start;
      numFilteredColumns = numFilterColumns;
      ArrayList<Layer> sortedLayers =  controllerOld.getSortByWeight();

      int n = numFilterColumns;
      for(int i = numFilters - 1; i >= 0; i--){
        int layerID = i;
        //println(layerID + " : " + data.getColumnName(layerID));
        if( i >= end ) {filtersChosen[layerID] = 0; continue;}
        
        if( n <= 0) {
          filtersChosen[layerID] = 0; 
//          if(layerID == start) {
//            filtersChosen[layerID] = 1;
//            numFilteredColumns++;
//          }
        }
        else  filtersChosen[layerID] = 1; 
        
        n--;
        
      }
  
      println(rnumFiltersSliderPos + " " + lnumFiltersSliderPos + "     " + numFilterColumns + " before set data");
      setData(false);
      controllerPrev = controller;
  
      // sort layers
      controller.sort();
      addData();
      computeDataMinMax();
      
      colorLayers();
      println("TWO CLICKS - OUT - AFTER COLOR LAYERS");
      layerIDtoStroke = -1;
      dbclickedLayer = -1;
      highlightedLayer = -1;
      loop();
}


void calculateSelectedFilter(){

  float dimy = (filterY2 - filterY1) / numFilters;
  int j = floor( (mouseY-filterY1)/dimy);
  
  j = numFilters - 1 - j;
  
  if( filtersChosen[j] == 0)
    filtersChosen[j] = 1;
  else if(numFilteredColumns != 1) filtersChosen[j] = 0;
  
  numFilteredColumns = 0;
  for(int i=0; i< numFilters; i++){
    if(filtersChosen[i] == 1) numFilteredColumns++; 
  }
}


void setSelectedLayerFilter(int layerID){
  
  numFilteredColumns = 1;
  filtersChosen[layerID] = 1;
  for(int i=0; i < numFilters; i++){
    if(i != layerID) filtersChosen[i] = 0; 
  }
}

void setAllFiltersTrue(){
  
  numFilteredColumns = columnCount;
  for(int i=0; i < numFilters; i++){
    filtersChosen[i] = 1; 
  }
}



void dottedLine(float x1, float y1, float x2, float y2, int lenDash, int spacing){
   
  float len_line = sqrt(pow((x2-x1),2) + pow((y2-y1),2));
   
  float divisions = (len_line / (lenDash + spacing));
   
  float div_len = (lenDash + spacing);
       
  float lenx = (x2-x1) / divisions; 
  float leny = (y2-y1) / divisions; 
  
  float dx = lenDash/(div_len) * lenx;
  float sx = spacing/(div_len) * lenx;
  
  float dy = lenDash/(div_len) * leny;
  float sy = spacing/(div_len) * leny;
  
  float s;
  for (s = 0; s < floor(divisions); s++){
      beginShape(LINES);
       vertex(x1 + s*(sx + dx), y1 + s*(sy + dy));
       vertex(x1 + s*(sx + dx) + dx, y1 + s*(sy + dy) + dy);
      endShape(); 
  }
  
  float rem = divisions - floor(divisions);
  
  rem = lenDash/(lenDash+ spacing) < rem ? lenDash/(lenDash+ spacing) : rem;
  
  if(rem > 0){

    beginShape(LINES);
       vertex(x1 + s*(sx + dx), y1 + s*(sy + dy));
       vertex(x1 + s*(sx + dx) + rem * lenx, y1 + s*(sy + dy) +  rem * leny);
      endShape(); 
    
  } 
  
}

